﻿using System;
using System.Collections.Generic;

namespace yunio
{
    using LitJson;

    public class YunioJson
    {
        internal StringComparison comparison = StringComparison.OrdinalIgnoreCase;
        internal const char path_splitchar = '.';
        internal JsonData obj { get; set; }
        internal string source { get; set; }
        public string JsonText { get { if (obj is not null) return obj.ToJson(); return source; } }
        public bool OK { get; internal set; } = true;
        public YunioJson(string json)
        {
            source = json;
            try { obj = JsonMapper.ToObject(new JsonReader(json)); }
            catch { OK = false; }
        }
        internal YunioJson(JsonData data)
        {
            obj = data;
        }
        public YunioJson()
        {
            obj = new JsonData();
            obj.EnsureDictionary();
        }
        public static YunioJson NewObj()
        {
            return new YunioJson();
        }
        public static YunioJson NewList()
        {
            var o = new JsonData();
            o.EnsureList();
            return new YunioJson(o);
        }
        public string ToJson()
        {
            return obj.ToJson();
        }
        public YunioJson SetText(string path, string text)
        {
            var name = read_name(ref path);
            JsonData data = find_data_autocreate(path);
            if (data.IsObject) data[name] = new JsonData(text);
            return this;
        }
        public YunioJson SetNumber(string path, decimal number)
        {
            var name = read_name(ref path);
            JsonData data = find_data_autocreate(path);
            if (data.IsObject) data[name] = new JsonData(number);
            return this;
        }
        public YunioJson SetBoolean(string path, bool value)
        {
            var name = read_name(ref path);
            JsonData data = find_data_autocreate(path);
            if (data.IsObject) data[name] = new JsonData(value);
            return this;
        }
        public YunioJson SetItem(string path, YunioJson item)
        {
            var name = read_name(ref path);
            JsonData data = find_data_autocreate(path);
            if (data.IsObject) data[name] = item.obj;
            return this;
        }
        public YunioJson AddArrayItem(string path, YunioJson item)
        {
            var name = read_name(ref path);
            JsonData data = find_data_autocreate(path);
            data = data[name];
            if (data.IsArray) data.Add(item.obj);
            return this;
        }
        internal static string read_name(ref string path)
        {
            var ix = path.LastIndexOf(path_splitchar);
            var name = path;
            if (ix ==-1)
            {
                path = string.Empty;
                return name;
            }

            path = path.Substring(0, ix);
            return name.Substring(ix + 1);

        }
        internal JsonData find_data_autocreate(string path)
        {
            JsonData data = obj;

            string key = string.Empty;
            if (!string.IsNullOrEmpty(path))
                foreach (var node in path.Split(path_splitchar))
                {
                    if ((key = data.FindKey(node, comparison)) != string.Empty)
                    {
                        data = data[key];
                        if (!data.IsObject) return null;
                        continue;
                    }
                    else data = new JsonData();

                }

            return data;
        }
        internal JsonData find_data(string path)
        {
            JsonData data = obj;

            string key = string.Empty;
            var name = read_name(ref path);
            if (!string.IsNullOrEmpty(path))
            foreach (var node in path.Split(path_splitchar))
            {
                if ((key = data.FindKey(node, comparison)) != string.Empty)
                {
                    data = data[key];
                    if (!data.IsObject) return null;
                    continue;
                }
                else return null;

            }

            if (string.IsNullOrEmpty(name)) return data;
            if (data.ContainsKey(name)) return data[name];
            return null;
        }
        public string Text(string path)
        {
            JsonData data = find_data(path);
            if (data == null) return default;
            if (data.IsObject || data.IsArray) return string.Empty;
            return data.ToString();
        }
        public decimal Number(string path)
        {
            JsonData data = find_data(path);
            if (data == null) return default;
            if (data.IsLong) return (long)data;
            else if (data.IsInt) return (int)data;
            return default;
        }
        public bool Bool(string path)
        {
            JsonData data = find_data(path);
            if (data == null) return default;
            if (data.IsBoolean) return (bool)data;
            return default;
        }
        public IEnumerable<YunioJson> LoopArray(string path)
        {
            JsonData data = find_data(path);
            if (data != null)
            if (data.IsArray) foreach (JsonData item in data) yield return new YunioJson(item);
        }
    }
}
